"""
 程序简介: 存储动漫基本数据并展示
 实现方法及技术:
 1.在线搜索
 1).通过TMDB的api接口获取到关键词搜索后的TvShow的ID
 2).通过TvShow的ID分别爬取简介页、分季页的内容
 3).解析这两页,获得需要的数据
 4).展示所得季信息,并要求用户输入要下载的季信息的编号
 5).通过季数分别爬取对应季详情页,并解析出集信息
 6).整合所有已获得的数据
 7).通过sqlite3操作sqlite数据库进行入库
 2.本地搜索
 1).通过sqlite3操作使用关键词(NAME)查找数据库获得对应本地ID(ID)
 2).通过本地ID获取到所需信息
 3).展示
 3.删除
 1).通过sqlite3操作使用关键词(NAME)查找数据库获取本地ID(ID)
 2).删除数据库中所有对应ID的数据
 -- 使用函数，各函数功能在对应位置均有注释

 使用技术:Python、Sqlite、网页爬虫、网络请求、json解析

 依赖:requests bs4

 原项目: 动画信息管理系统(By 刘正义 use Java)
 该项目已经进行精简
 Python版本: python 3.7.6(for macOS)
 兼容性：Windows10 X64 2004 [OK],macOS10.15.5 [OK]
 使用TheMovieDB作为数据源
 @author JusticeLiu(刘正义)

 TODO: 手动添加数据(由于程序太过庞大,该操作移除)
 TODO: 修改数据(由于程序太过庞大,该操作移除)
 TODO: 搜索
 TODO: 随机(由于程序太过庞大,该操作移除)
 TODO: 查看数据
 FIXME: 数据库去重(由于程序太过庞大,该操作移除)
 FIXME: 堆栈会随操作次数的增加最终溢出(懒得改了)
"""
import requests
import re
import json
from bs4 import BeautifulSoup
import os
import platform
import sqlite3

# 此处配置需要的参数
# API_KEY为TheMovieDB提供,api_key所有者:zhengyi
API_KEY = 'af3638823b154037b95d29fbbdbd4b78'  # TMDB API KEY
SQL_FILE_NAME = '19326240005-刘正义-数字媒体基础春季班-动画信息管理系统.db'  # 数据库文件


# 清屏-兼容性保护
def clear():
    pf = platform.platform()
    if 'Windows' in pf:
        os.system('cls')
    else:
        os.system('clear')


# 基础功能
def home():
    clear()
    print('''
    ------- 正义VideoSite后端数据管理程序 ----------
        [1]: 添加数据
        [2]: 搜索
        [3]: 随机获取(不可用)
        [4]: 变更数据(不可用)
        [5]: 删除
        [q]: 退出程序
    ---------------------------------------------
    ''')
    sel = input('请输入选项:')
    if sel == '1':
        addDataPage()
    elif sel == '2':
        searchDataBasePage()
    elif sel == '3':
        pass
    elif sel == '4':
        pass
    elif sel == '5':
        delDataPage()
    elif sel == 'q':
        exit(0)
    else:
        print("输入数字不合法")
        return


# 搜索本地库-二级页面
def searchDataBasePage(err=''):
    clear()
    if err != '':
        print('ERROR:' + err)
    print('''
    ---------------- 搜索(输入q退出) ------------------
    ''')
    keyWord = input('请输入关键词:')
    if keyWord == 'q':
        return
    mid = searchDataBaseByName(keyWord)
    if mid == 0:
        searchDataBasePage('未搜索到结果')
        return
    showDetailsPage(mid)


# 详情页
def showDetailsPage(mid=0):
    clear()
    data = searchDataBaseByID(mid)
    aid = data['aid']
    title = data['title']
    ov = data['overview']
    g = data['genres']
    fs = data['sc']
    ds = data['ds']
    de = data['de']
    print('''
    -------------------------- 电视节目详情 --------------------------
        ID: {}      AID: {}        标题: {}
        
        剧情简介:
        {}
        
        类型: {}
        总季数:{}    已下载: {} 季度 {} 集
    ----------------------------- 操作 ------------------------------
    [1]:查看季度信息(不可用)
    [2]:查看剧集信息(不可用)
    [3]:修改数据(不可用)
    [4]:删除本条目
    [q]:退回主页
    ----------------------------------------------------------------
    '''.format(str(mid), str(aid), title, ov, g, str(fs), str(ds), str(de)))
    sel = input('    请输入操作编号:')
    if sel == '1':
        pass
    elif sel == '2':
        pass
    elif sel == '3':
        pass
    elif sel == '4':
        delFromDataBase(mid)
    elif sel == 'q':
        return
    else:
        print('    ERROR:不合法操作')
        exit(1)


# 添加数据-二级页面
def addDataPage(err=''):
    clear()
    if err != '':
        print('ERROR:' + err)
    print('''
    ----------------- 添加数据 -------------------
    [1]: 在线搜索
    [2]: 手动输入(不可用)
    [q]: 退回主页
    ---------------------------------------------
    ''')

    sel = input('请输入选项:')
    if sel == '1':
        onlineSearchPage()
    elif sel == 'q':
        return
    else:
        print("输入数字不合法")
        home()


# 删除数据二级页面
def delDataPage():
    clear()
    print('''
    ------------------- 删除数据 -------------------
    请输入要删除的id:
    -----------------------------------------------
    ''')
    key = input()
    delFromDataBase(key)


# 在线搜索操作界面
def onlineSearchPage():
    clear()
    keyWord = input('请输入关键词:')
    # 搜索电视节目
    aid = searchTvShow(keyWord)
    if aid == 0:
        addDataPage('未搜索到"' + keyWord + '"')
    clear()
    # 检索电视节目信息
    baseInfo = getTvShow(aid)
    # 检索季信息
    seasonInfo = getSeason(aid)
    if seasonInfo == 0:
        addDataPage('无法使用该aid')
    # 检索按集信息
    print('------------ 请选择要载入的季数(以空格分割) ----------------')
    sel = input()
    selSeason = sel.split(' ')
    clear()
    episodeSel = []
    for i in selSeason:
        try:
            j = int(i)
            episodeInfo = getEpisode(aid, j)
            if episodeInfo != 0:
                episodeSel.append({'season': j, 'episodeInfo': episodeInfo})
            else:
                print('无法检索季:' + i)
        except ValueError:
            pass
    # 整合数据
    o = {'aid': aid, 'animate': baseInfo, 'season': seasonInfo, 'episode': episodeSel}
    addToDataBase(o)


# 搜索电视节目
def searchTvShow(keyWord):
    clear()
    response = requests.get(
        'https://api.themoviedb.org/3/search/tv?api_key=' + API_KEY + '&language=zh-CN&page=1&query=' + keyWord + '&include_adult=false')
    # print(response.content)
    result = json.loads(response.content)
    if result['total_results'] == 0:
        print('没有搜索到结果')
        return 0

    result = result['results']

    print('注意:此处仅会显示20个结果(即搜索结果第一页)')
    j = 1
    for i in result:
        print('[' + str(j) + ']:' + i['name'] + '\t' + str(i['id']))
        j = j + 1
    sel = int(input('请输入要选中的id:'))
    try:
        return result[sel - 1]['id']
    except IndexError:
        print('您输入的选项不合法')
        return 0


# 获取电视节目信息
def getTvShow(aid):
    response = requests.get('https://www.themoviedb.org/tv/' + str(aid) + '?language=zh-CN').content
    bs = BeautifulSoup(response, 'html.parser')
    # 解析标题
    title = bs.find(class_='title').find('h2').find('a').get_text()
    # 解析类型
    genres = bs.find(class_='genres').get_text()
    # 修正类型
    genres = genres.replace('\n', '')
    genres = genres.replace('\xa0', '')
    genres = genres.split(',')
    # 演员
    people = bs.find_all(class_='people')[1].find_all(class_='card')
    peopleList = []
    for i in people:
        peopleList.append(i.find('p').get_text())
    # 简介
    overview = bs.find(class_='overview').find_all('p')
    overviewText = ''
    for i in overview:
        overviewText += i.get_text()
        overviewText += '\n'

    baseInfo = {'title': title, 'genresList': {'genresList': genres}, 'peopleList': {'peopleList': peopleList},
                'overview': overviewText}
    return baseInfo


# 获取季信息
def getSeason(aid):
    h = requests.get('https://www.themoviedb.org/tv/' + str(aid) + '/seasons?language=zh-CN').content
    soup = BeautifulSoup(h, 'html.parser')

    title = soup.find_all(class_='title')[0].find_all('a')[0].get_text()
    print('title:' + str(title))
    seasonWrapper = soup.find_all(class_="season_wrapper")

    list = []

    for item in seasonWrapper:
        seasonID = item.find_all('p')[0].get_text()
        try:
            p = int(re.findall(r'第(.*?)季', seasonID)[0])
        except TypeError:
            p = 0
        seasonYear = item.find_all('h4')[0].get_text().split('|')[0]
        seasonEpisode = item.find_all('h4')[0].get_text().split('|')[1]
        tmp = {'seasonID': p, 'seasonYear': seasonYear, 'seasonEpisode': seasonEpisode}
        list.append(tmp)

    for i in list:
        print('season:' + str(i['seasonID']), end='\t')
        print('seasonYear:' + str(i['seasonYear']), end='\t')
        print('seasonEpisode:' + str(i['seasonEpisode']))

    if len(list) != 0:
        return list
    else:
        return 0


# 获取剧集信息
def getEpisode(aid, season):
    site = requests.get(
        'https://www.themoviedb.org/tv/' + str(aid) + '/season/' + str(season) + '?language=zh-CN').content
    soup = BeautifulSoup(site, 'html.parser')
    card = soup.find_all(class_='card')
    episodeList = []
    for i in card:
        episode = int(i.find_all(class_='episode_number')[0].get_text())
        title = i.find_all('h3')[0].get_text()
        introduce = i.find_all(class_='overview')[0].find_all('p')[0].get_text()
        tmp = {'episode': episode, 'title': title, 'info': introduce}
        episodeList.append(tmp)
    # print(episodeList)

    for i in episodeList:
        print('EpisodeNumber:' + str(i['episode']), end='\t')
        print('EpisodeTitle:' + str(i['title']), end='\n')
        # print('EpisodeIntroduce:' + str(i['info']))
    print('all_length:' + str(len(episodeList)))
    print('------------------------------------------------------------')
    if len(episodeList) != 0:
        return episodeList
    else:
        return 0


def s(s):
    s = s.replace('\'', '\"')
    return '\'' + str(s) + '\''


# 添加到数据库
def addToDataBase(obj):
    conn = sqlite3.connect(SQL_FILE_NAME)
    c = conn.cursor()
    # 获取可用id
    table = c.execute('SELECT * from ANIMATE')
    key = 0
    for i in table:
        key = i[0]
    key += 1
    # 整理数据
    animate = obj['animate']
    season = obj['season']
    episode = obj['episode']
    aid = obj['aid']
    name = animate['title']
    # ANIMATE 表
    genres = str(animate['genresList'])
    people = str(animate['peopleList'])
    overview = animate['overview']
    c.execute("INSERT INTO ANIMATE (ID, AID, NAME, GENRES, PEOPLE, OVERVIEW) "
              "VALUES ({}, {}, {}, {}, {}, {})"
              .format(str(key), str(aid), s(name), s(genres), s(people), s(overview)))
    # SEASON 表
    for i in season:
        season = i['seasonID']
        seasonYear = i['seasonYear']
        seasonEpisode = int(re.findall(r'(.*?) 集', i['seasonEpisode'])[0])
        c.execute("INSERT INTO SEASON (ID, AID, NAME, SEASON, SEASON_YEAR, EP_LEN) "
                  "VALUES ({}, {}, {}, {}, {}, {})"
                  .format(str(key), str(aid), s(name), str(season), str(seasonYear), str(seasonEpisode)))
    # EPISODE 表
    for i in episode:
        season = i['season']
        for j in i['episodeInfo']:
            episodeID = j['episode']
            title = j['title']
            info = j['info']
            c.execute("INSERT INTO EPISODE (ID, AID, SEASON, EPISODE, TITLE, INFO) "
                      "VALUES ({}, {}, {}, {}, {}, {})"
                      .format(str(key), str(aid), str(season), str(episodeID), s(title), s(info)))
    conn.commit()
    conn.close()
    return


# 从数据库删除
def delFromDataBase(key):
    conn = sqlite3.connect(SQL_FILE_NAME)
    cur = conn.cursor()

    cur.execute("DELETE from ANIMATE where ID=" + str(key))
    cur.execute("DELETE from SEASON where ID=" + str(key))
    cur.execute("DELETE from EPISODE where ID=" + str(key))

    conn.commit()
    conn.close()
    return


# 搜索数据库-id
def searchDataBaseByID(mid):
    conn = sqlite3.connect(SQL_FILE_NAME)
    cur = conn.cursor()
    animate = cur.execute("SELECT ID, AID, NAME, GENRES, PEOPLE, OVERVIEW FROM ANIMATE where ID={}".format(str(mid)))
    cur = conn.cursor()
    season = cur.execute("SELECT ID, AID, NAME, SEASON, SEASON_YEAR, EP_LEN FROM SEASON where ID={}".format(str(mid)))
    cur = conn.cursor()
    episode = cur.execute("SELECT ID, AID, SEASON, EPISODE, TITLE, INFO FROM EPISODE where ID={}".format(str(mid)))

    aid = 0
    downloadedSeasonList = []
    downloadedSeason = 0
    downloadedEpisode = 0
    seasonCount = 0
    title = ''
    overview = ''
    genresList = []
    genres = ''

    for i in animate:
        title = i[2]
        aid = i[1]
        overview = i[5]
        genresList = json.loads(i[3])['genresList']
    for i in season:
        seasonCount += 1
    for i in episode:
        if i[2] in downloadedSeasonList:
            pass
        else:
            downloadedSeasonList.append(i[2])
            downloadedSeason += 1
        downloadedEpisode += 1
    for i in genresList:
        genres += i + ', '
    genres += '\b\b '
    conn.commit()
    conn.close()
    return {
        'id': mid,
        'aid': aid,
        'ds': downloadedSeason,
        'de': downloadedEpisode,
        'sc': seasonCount,
        'title': title,
        'overview': overview,
        'genres': genres
    }


def searchDataBaseByName(name):
    selId = 0
    conn = sqlite3.connect(SQL_FILE_NAME)
    cur = conn.cursor()
    animate = cur.execute("SELECT ID, NAME from ANIMATE where NAME='{}'".format(name))
    idTable = []
    k = 1
    clear()
    for i in animate:
        print('[{}]: {}'.format(str(k), i[1]))
        idTable.append(i[0])
        k += 1
    if len(idTable) == 0:
        print('未搜索到结果')
        return 0
    sel = input('请选择:')
    try:
        selId = idTable[int(sel) - 1]
    except:
        print('操作不合法')
        exit(1)
    conn.commit()
    conn.close()

    return selId


if __name__ == '__main__':
    # 启动程序
    while True:
        home()
